/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020.
 * Description: support rtos per-task swxn switch
 * Author: hejiani
 * Create: 2020-10-21
 */
#include <internal/rtos_swxn.h>
#include <linux/task_struct_extend.h>
#include <linux/seq_file.h>
#include <linux/mman.h>
#include <linux/unistd.h>
#include "internal.h"

static int pid_swxn_show(struct seq_file *m, void *v)
{
	struct inode *inode = m->private;
	struct task_struct *p = NULL;
	struct rtos_task_struct *rtos_task = NULL;

	p = get_proc_task(inode);
	if (!p)
		return -ESRCH;

	rtos_task = task_to_rtos_task(p);
	if (!rtos_task) {
		put_task_struct(p);
		return -ESRCH;
	}

	seq_printf(m, "%u\n", rtos_task->swxn);
	put_task_struct(p);

	return 0;
}

static int pid_swxn_single_open(struct inode *inode, struct file *file)
{
	return single_open(file, pid_swxn_show, inode);
}

static ssize_t pid_swxn_read(struct file *file, char __user *buf,
		size_t count, loff_t *ppos)
{
	if (!capable(get_swxn_cap()))
		return -EPERM;

	return seq_read(file, buf, count, ppos);
}

static ssize_t pid_swxn_write(struct file *file, const char __user *buf,
		size_t count, loff_t *ppos)
{
	struct inode *inode = file_inode(file);
	struct task_struct *p = NULL;
	struct rtos_task_struct *rtos_task = NULL;
	ssize_t result;
	unsigned int set_pid_swxn;

	if (!capable(get_swxn_cap()))
		return -EPERM;

	if (*ppos != 0)
		return -EINVAL;

	result = kstrtouint_from_user(buf, count, 0, &set_pid_swxn);
	if (result < 0)
		return -EINVAL;

	if (set_pid_swxn < get_swxn_status() || set_pid_swxn > SWXN_DISABLE)
		return -EINVAL;

	p = get_proc_task(inode);
	if (!p)
		return -ESRCH;

	rtos_task = task_to_rtos_task(p);
	if (!rtos_task) {
		put_task_struct(p);
		return -ESRCH;
	}
	rtos_task->swxn = set_pid_swxn;

	put_task_struct(p);

	return count;
}

const struct file_operations proc_pid_swxn_operations = {
	.open = pid_swxn_single_open,
	.read = pid_swxn_read,
	.write = pid_swxn_write,
	.llseek = seq_lseek,
	.release = single_release,
};
